package com.example.horizonserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.horizonserver.common.context.BaseContext;
import com.example.horizonserver.common.exception.DispatchBusinessException;
import com.example.horizonserver.common.exception.VehicleEecption;
import com.example.horizonserver.common.result.PageResult;
import com.example.horizonserver.config.RabbitConfig;
import com.example.horizonserver.mapper.DispatchMapper;
import com.example.horizonserver.mapper.VehicleMapper;
import com.example.horizonserver.pojo.DTO.*;
import com.example.horizonserver.pojo.VO.DispatchSubmitVO;
import com.example.horizonserver.pojo.entity.Dispatch;
import com.example.horizonserver.pojo.entity.Vehicle;
import com.example.horizonserver.pojo.message.DispatchVehicleMessage;
import com.example.horizonserver.service.DispatchService;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class DispatchServiceImpl extends ServiceImpl<DispatchMapper,Dispatch> implements DispatchService {

    private final DispatchMapper dispatchMapper;

    private final VehicleMapper vehicleMapper;

    private final RabbitTemplate rabbitTemplate;

    /**
     * 提交用车申请
     * @param dispatchSubmitDTO
     * @return
     */
    @Transactional
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "dispatchPageCache", allEntries = true),
            @CacheEvict(cacheNames = "vehiclePageCache", allEntries = true)
    })
    public DispatchSubmitVO submitDispatch(DispatchSubmitDTO dispatchSubmitDTO) {
        //判断车辆状态,只有为可用的时候才能进行后续操作
        Vehicle vehicle = vehicleMapper.selectById(dispatchSubmitDTO.getVehicleId());
        if(vehicle.getStatus() != 1)
        {
            throw new DispatchBusinessException("车辆状态不可用");
        }
        //向调度表中插入数据
        Dispatch dispatch = new Dispatch();
        BeanUtils.copyProperties(dispatchSubmitDTO,dispatch);
        //补充剩余参数
        dispatch.setId(null);
        dispatch.setUseTime(LocalDateTime.now());
        //使用时间戳作为调度记录号
        dispatch.setNumber(String.valueOf(System.currentTimeMillis()));
        //状态设置为待处理
        dispatch.setStatus(1);
        //如果当前用户是管理员,则直接通过用车申请,反之则等待管理员批准
        //获取当前用户id与用户role
        Integer userId = BaseContext.getCurrentId();
        dispatch.setUserId(userId);
        Integer userRole = BaseContext.getCurrentRole();
        if(userRole == 1)
        {
            dispatch.setStatus(3);
        }
        dispatchMapper.insert(dispatch);
        //不再调用vehiclemapper,用Rabbitmq实现异步解耦
        // ===== 使用 RabbitMQ 异步处理车辆状态 =====
        DispatchVehicleMessage message = DispatchVehicleMessage.builder()
                .dispatchId(dispatch.getId())
                .vehicleId(dispatch.getVehicleId())
                .userRole(userRole)
                .action("SUBMIT")//SUBMIT表示提交申请
                .LastUseTime(dispatch.getUseTime())
                .build();
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE, RabbitConfig.DISPATCH_ROUTING_KEY, message);
        return DispatchSubmitVO.builder()
                .id(dispatch.getId())
                .dispatchNumber(dispatch.getNumber())
                .useTime(dispatch.getUseTime())
                .build();
    }

    /**
     * 管理员同意用车申请
     * @param dispatchConfirmDTO
     */
    @Transactional
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "dispatchPageCache", allEntries = true),
            @CacheEvict(cacheNames = "vehiclePageCache", allEntries = true)
    })
    public void confirm(DispatchConfirmDTO dispatchConfirmDTO) {
        //根据id查询调度记录
        Dispatch dispatchDB = dispatchMapper.selectById(dispatchConfirmDTO.getId());
        //调度记录只有存在且状态为1（待处理时）才可以通过
        if (dispatchDB == null || !dispatchDB.getStatus().equals(1) ){
            throw new DispatchBusinessException("调度状态不合法");
        }
        dispatchMapper.update(Wrappers.<Dispatch>lambdaUpdate()
                .eq(Dispatch::getId, dispatchConfirmDTO.getId())
                .set(Dispatch::getStatus, 3)
                .set(Dispatch::getUseTime, LocalDateTime.now()));
        //更新车辆状态为在用 RabbitMQ异步调用
        Dispatch dispatch = dispatchMapper.selectById(dispatchConfirmDTO.getId());
        DispatchVehicleMessage message = DispatchVehicleMessage.builder()
                .dispatchId(dispatch.getId())
                .vehicleId(dispatch.getVehicleId())
                .action("CONFIRM")//CONFIRM表示通过申请
                .LastUseTime(dispatch.getUseTime())
                .build();
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE,RabbitConfig.DISPATCH_ROUTING_KEY,message);
    }

    /**
     * 管理员拒绝用车申请
     * @param dispatchRejectionDTO
     */
    @Transactional
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "dispatchPageCache", allEntries = true),
            @CacheEvict(cacheNames = "vehiclePageCache", allEntries = true)
    })
    public void rejection(DispatchRejectionDTO dispatchRejectionDTO) {
        // 根据id查询调度记录
        Dispatch dispatchDB = dispatchMapper.selectById(dispatchRejectionDTO.getId());
        // 订单只有存在且状态为1（待处理时）才可以驳回
        if (dispatchDB == null || !dispatchDB.getStatus().equals(1) ){
            throw new DispatchBusinessException("调度状态不合法");
        }
        dispatchMapper.update(Wrappers.<Dispatch>lambdaUpdate()
                .eq(Dispatch::getId,dispatchDB.getId())
                .set(Dispatch::getStatus, 4)//状态设置为拒绝
                .set(Dispatch::getRejectReason, dispatchRejectionDTO.getRejectionReason())
                .set(Dispatch::getUseTime, LocalDateTime.now())
                .set(Dispatch::getCost, BigDecimal.valueOf(0)));
        // 更新车辆状态
        DispatchVehicleMessage message = DispatchVehicleMessage.builder()
                .dispatchId(dispatchDB.getId())
                .vehicleId(dispatchDB.getVehicleId())
                .action("REJECTION")//REJECTION表示拒绝申请
                .LastUseTime(dispatchDB.getUseTime())
                .build();
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE,RabbitConfig.DISPATCH_ROUTING_KEY,message);
    }

    /**
     * 完成用车申请,归还车辆
     * @param dispatchCompleteDTO
     */
    @Transactional
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "dispatchPageCache", allEntries = true),
            @CacheEvict(cacheNames = "vehiclePageCache", allEntries = true)
    })
    public void complete(DispatchCompleteDTO dispatchCompleteDTO) {
        //判断当前还车用户id是否是当前调度记录中的userId
        Integer currentId = BaseContext.getCurrentId();
        //找到车id中状态是在用的订单
        Dispatch dispatch = getOne(Wrappers.<Dispatch>lambdaQuery()
                .eq(Dispatch::getVehicleId, dispatchCompleteDTO.getVehicleId())
                .eq(Dispatch::getStatus, 3));
        if(!Objects.equals(dispatch.getUserId(), currentId))
        {
            throw new DispatchBusinessException("当前用户不是该车辆的使用者");
        }
        dispatchMapper.update(dispatch,Wrappers.<Dispatch>lambdaUpdate()
                .eq(Dispatch::getId,dispatch.getId())
                .set(Dispatch::getStatus, 2)//状态设置为完成
                .set(Dispatch::getCost, dispatchCompleteDTO.getCost())
                .set(Dispatch::getUseTime, LocalDateTime.now()));
        //更新车辆状态为可用
        DispatchVehicleMessage message = DispatchVehicleMessage.builder()
                .dispatchId(dispatch.getId())
                .vehicleId(dispatch.getVehicleId())
                .action("COMPLETE")//COMPLETE表示完成申请
                .LastUseTime(dispatch.getUseTime())
                .build();
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE,RabbitConfig.DISPATCH_ROUTING_KEY,message);
    }

    /**
     * 分页条件查询车辆调度记录
     *
     * @param dispatchPageQueryDTO
     * @return
     */
    @Override
    @Cacheable(
            value = "dispatchPageCache",
            key = "'page:' + #dispatchPageQueryDTO.page + ':' + #dispatchPageQueryDTO.pageSize",
            condition = "#dispatchPageQueryDTO.pageSize==9999"+
                    "&&(#dispatchPageQueryDTO.status == null || #dispatchPageQueryDTO.status == '') " +
                    "&& (#dispatchPageQueryDTO.beginTime == null || #dispatchPageQueryDTO.beginTime == '') " +
                    "&& #dispatchPageQueryDTO.endTime == null || #dispatchPageQueryDTO.endTime == ''"
    )
    public PageResult pageQuery(DispatchPageQueryDTO dispatchPageQueryDTO) {
        if(dispatchPageQueryDTO.getPage()==null||dispatchPageQueryDTO.getPageSize()==null)
        {
            throw new DispatchBusinessException("未指定页数以及每页数据数");
        }
        //判断status是否符合规矩
        if(dispatchPageQueryDTO.getStatus() != null && dispatchPageQueryDTO.getStatus() != 1
                && dispatchPageQueryDTO.getStatus() != 2&& dispatchPageQueryDTO.getStatus() != 3
                && dispatchPageQueryDTO.getStatus() != 4)
        {
            throw new VehicleEecption("调度状态不合法");
        }
        // 构建分页参数
        Page<Dispatch> page = new Page<>(dispatchPageQueryDTO.getPage(), dispatchPageQueryDTO.getPageSize());
        // 构建查询条件（使用普通 QueryWrapper 而非 LambdaQueryWrapper）
        QueryWrapper<Dispatch> qw = new QueryWrapper<>();
        // 显式指定表别名 d（与 SQL 中的表别名保持一致）
        qw.eq(dispatchPageQueryDTO.getStatus() != null, "d.status", dispatchPageQueryDTO.getStatus());
        qw.ge(dispatchPageQueryDTO.getBeginTime() != null, "use_time", dispatchPageQueryDTO.getBeginTime());
        qw.le(dispatchPageQueryDTO.getEndTime() != null, "use_time", dispatchPageQueryDTO.getEndTime());
        // 执行分页查询
        IPage<Dispatch> dispatchPage = dispatchMapper.selectPageWithRelations(page, qw);
        // 封装返回结果
        PageResult pageResult = new PageResult();
        pageResult.setTotal(dispatchPage.getTotal());
        pageResult.setRecords(dispatchPage.getRecords());
        return pageResult;
    }


}
